home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995…tember: Reference Library / Dev.CD Sep 95 RL / Dev.CD Sep 95 RL.toast / mac / Technical Documentation / develop / develop Issue 20 code / Scripting the Finder / Finder Snapshot / SaveWindows.cp < prev    next >
Encoding:
Text File  |  1994-10-04  |  24.7 KB  |  832 lines  |  [TEXT/MMCC]

  1. /*================================================================================
  2.     SaveWindows.cp
  3.     
  4.     ©1994 Greg Anderson
  5.     greggor@apple.com
  6.     
  7.     Send events to the Finder
  8.         
  9. ================================================================================*/
  10. #include "SaveWindows.h"
  11. #include "AppleEventUtilities.h"
  12. #include "AERegistry.h"
  13. #include "AEObjects.h"
  14. #include "FinderRegistry.h"
  15.  
  16. #ifndef Exceptions_h
  17. #include "Exceptions.h"
  18. #endif
  19.  
  20. //----------------------------------------------------------------------------------------
  21. // FindPSNbyTypeAndSig: 
  22. //
  23. //    Find the PSN of some process, given its type and creator
  24. //----------------------------------------------------------------------------------------
  25. void FindPSNbyTypeAndSig(ProcessSerialNumber* psn, OSType type, OSType sig)
  26. {    
  27.     ProcessInfoRec            theProc;
  28.         
  29.     //
  30.     // Start out with kNoProcess
  31.     //
  32.     psn->highLongOfPSN = 0;
  33.     psn->lowLongOfPSN = kNoProcess;
  34.     
  35.     //
  36.     // Initialize fields in the ProcessInfoRec,
  37.     // or we'll have memory hits in random locations
  38.     //
  39.     theProc.processInfoLength = sizeof( ProcessInfoRec );
  40.     theProc.processName = nil;
  41.     theProc.processAppSpec = nil;
  42.     theProc.processLocation = nil;
  43.     
  44.     while(true)
  45.     {
  46.         OSErr        theErr;
  47.         
  48.         //
  49.         // Keep looking for the process until we find it
  50.         //
  51.         FailErr(GetNextProcess(psn));
  52.         
  53.         //
  54.         // Is the current process the one we're looking for?
  55.         //
  56.         FailErr(GetProcessInformation(psn, &theProc));
  57.         if( (theProc.processType == type ) && (theProc.processSignature == sig) )
  58.             break;
  59.     }
  60. } // FindPSNbyTypeAndSig 
  61.  
  62. //----------------------------------------------------------------------------------------
  63. // GetAddressOfFinder: 
  64. //
  65. //    Generate an address for the Finder on this machine 
  66. //----------------------------------------------------------------------------------------
  67. TDescriptor GetAddressOfFinder()
  68. {
  69.     ProcessSerialNumber finderPSN;
  70.     TDescriptor finderAddressDescriptor;
  71.     
  72.     //
  73.     // Find the Finder's PSN
  74.     //
  75.     FindPSNbyTypeAndSig(&finderPSN, 'FNDR', 'MACS');
  76.     
  77.     //
  78.     // Copy the target ID into a descriptor
  79.     //
  80.     finderAddressDescriptor.MakeProcessSerialNumber(finderPSN);
  81.     
  82.     return finderAddressDescriptor;
  83. } // GetAddressOfFinder 
  84.  
  85. //----------------------------------------------------------------------------------------
  86. // MakeSpecifierForSelection
  87. //----------------------------------------------------------------------------------------
  88. TDescriptor MakeSpecifierForSelection()
  89. {
  90.     TDescriptor selectionSpecifier; 
  91.     TDescriptor nullDescriptor;
  92.     TDescriptor keyData;
  93.  
  94.     //
  95.     // Make a descriptor whose type is 'typeType' and whose
  96.     // contents are 'pSelection' (defined in FinderRegistry.h).
  97.     // This descriptor specifies the property of the null container
  98.     // that we are interested in--in this case, the selection.
  99.     //
  100.     keyData.MakeDescType(pSelection);
  101.     
  102.     //
  103.     // Make an object specifier for "selection of <null container>".
  104.     // The object specifier will contain the following:
  105.     //
  106.     // Desired class:        cProperty        Object specifiers that
  107.     //                                        specify properties always
  108.     //                                        have a desired class of cProperty
  109.     //
  110.     // Container:            null            A null descriptor specifies the
  111.     //                                        null container.  Object specifiers
  112.     //                                        almost always terminate with the
  113.     //                                        null descriptor, the only exceptions
  114.     //                                        being specifiers used to support
  115.     //                                        "paste reference," which terminate
  116.     //                                        in the PSN of the process that
  117.     //                                        generated them, and object specifiers
  118.     //                                        contained in test descriptors
  119.     //                                        (found in "whose" clauses) that
  120.     //                                        often terminate with "object being
  121.     //                                        examined".
  122.     //
  123.     // Key form:            formPropertyID    Object specifiers that specify properties
  124.     //                                        always have a key form of formPropertyID.
  125.     //
  126.     // Key data:            typeType /        The key data descriptor of a property
  127.     //                        pSelection        must always be of type typeType; in
  128.     //                                        our case, it is a descriptor that
  129.     //                                        contains pSelection (built above).
  130.     //
  131.     // We pass 'true' to MakeObjectSpecifier, so it will always dispose its inputs.
  132.     // If we passed in 'false', we would have to dispose of the keyData descriptor
  133.     // ourselves.
  134.     //
  135.     selectionSpecifier.MakeObjectSpecifier(    cProperty,
  136.                                             nullDescriptor,
  137.                                             formPropertyID,
  138.                                             keyData,
  139.                                             true);
  140.  
  141.     return selectionSpecifier;
  142. } // MakeSpecifierForSelection
  143.  
  144. //----------------------------------------------------------------------------------------
  145. // MakeSpecifierForIndexedItem
  146. //----------------------------------------------------------------------------------------
  147. TDescriptor MakeSpecifierForIndexedItem(DescType desiredClass, long index, TDescriptor ofSpecifier)
  148. {
  149.     TDescriptor resultSpecifier; 
  150.     TDescriptor keyData;
  151.  
  152.     //
  153.     // Make a descriptor whose type is 'typeLongInteger' and whose
  154.     // contents is the index passed in.
  155.     //
  156.     keyData.MakeLong(index);
  157.     
  158.     //
  159.     // Make an object specifier for "<<class desiredClass>> index of <ofSpecifier>".
  160.     // The object specifier will contain the following:
  161.     //
  162.     // Desired class:        desiredClass            The class of the object being
  163.     //                                                referenced examples include cWindow,
  164.     //                                                cObject, cDisk, cAliasFile, and
  165.     //                                                many others
  166.     //
  167.     // Container:            ofSpecifier                Object specifiers are defined
  168.     //                                                recursively
  169.     //
  170.     // Key form:            formAbsolutePosition    This indicates that we are accessing
  171.     //                                                the 'index'th item of the container.
  172.     //                                                Another choice would be formName, in
  173.     //                                                which case the key data would
  174.     //                                                contain the name of the object being
  175.     //                                                referenced.
  176.     //
  177.     // Key data:            typeLongInteger /        formAbsolutePosition implies that 
  178.     //                        'index'                    the key data will be an integer
  179.     //
  180.     // We pass 'false' to MakeObjectSpecifier, so our inputs are not disposed
  181.     // (we want to keep 'ofSpecifier' around).  Because we didn't ask MakeObjectSpecifier
  182.     // to delete our inputs, we'll have to delete the key data ourselves
  183.     //
  184.     resultSpecifier.MakeObjectSpecifier(    desiredClass,
  185.                                             ofSpecifier,
  186.                                             formAbsolutePosition,
  187.                                             keyData,
  188.                                             false);
  189.     keyData.Dispose();
  190.  
  191.     return resultSpecifier;
  192. } // MakeSpecifierForSelection
  193.  
  194. //----------------------------------------------------------------------------------------
  195. // MakeSpecifierForFrontWindow
  196. //----------------------------------------------------------------------------------------
  197. TDescriptor MakeSpecifierForFrontWindow()
  198. {
  199.     TDescriptor nullDescriptor;
  200.     
  201.     return MakeSpecifierForIndexedItem(cWindow, 1, nullDescriptor);
  202. }
  203.  
  204. //----------------------------------------------------------------------------------------
  205. // MakeSpecifierForPropertyOfSpecifier: 
  206. //
  207. //    This function makes an object specifier for "property of <<specifier provided>>"
  208. //----------------------------------------------------------------------------------------
  209. TDescriptor MakeSpecifierForPropertyOfSpecifier(DescType property, TDescriptor ofSpecifier)
  210. {
  211.     TDescriptor specifier;
  212.     TDescriptor keyData;
  213.     OSErr err = noErr;
  214.         
  215.     //
  216.     // Make a descriptor whose type is 'typeType', and whose
  217.     // contents are the property passed into this function.
  218.     //
  219.     keyData.MakeDescType(property);
  220.  
  221.     Try
  222.     {
  223.         //
  224.         // The next object specifier we make also specifies a property, so it
  225.         // will look very similar to the one we built above:
  226.         //
  227.         // Desired class        cProperty        Required to specify a property.
  228.         //
  229.         // Container            "ofSpecifier"    We are making a specifier for
  230.         //                                        "property of <ofSpecifier>", so clearly
  231.         //                                        our container must be the
  232.         //                                        object specifier passed in.
  233.         //
  234.         // Key form:            formPropertyID    Required to specify a property.
  235.         //
  236.         // Key data                typeType /        As before, the key data descriptor
  237.         //                        property        is typeType, and contains the property ID
  238.         //                                        that we wish to specify.
  239.         //
  240.         // This time we pass 'false' to MakeObjectSpecifier so that it will NOT dispose
  241.         // of its inputs when it is done.  Doing this leaves the keyData and ofSpecifier
  242.         // descriptors intact; we dispose of the key data, but leave the specifier that
  243.         // was passed into this function the responsibility of the caller.
  244.         //
  245.         specifier.MakeObjectSpecifier(    cProperty,
  246.                                         ofSpecifier,
  247.                                         formPropertyID,
  248.                                         keyData,
  249.                                         false);
  250.         keyData.Dispose();
  251.     }
  252.     Catch(err)
  253.     {
  254.         //
  255.         // Note that 'MakeObjectSpecifier' might fail (out of memory, for example),
  256.         // so we must catch failures to dispose of the key data descriptor if necessary.
  257.         //
  258.         keyData.Dispose();
  259.         Throw(err);
  260.     }
  261.         
  262.     return specifier;
  263. } // MakeSpecifierForPropertyOfSpecifier 
  264.  
  265. //----------------------------------------------------------------------------------------
  266. // MakeSpecifierForPropertyOfSelection: 
  267. //
  268. //    This function makes an object specifier for "property of selection"
  269. //----------------------------------------------------------------------------------------
  270. TDescriptor MakeSpecifierForPropertyOfSelection(DescType property)
  271. {
  272.     TDescriptor specifier;
  273.     TDescriptor selectionSpecifier; 
  274.     TDescriptor keyData;
  275.     OSErr err = noErr;
  276.     
  277.     //
  278.     // Build an object specifier for "selection of <null container>"
  279.     //
  280.     selectionSpecifier = MakeSpecifierForSelection();
  281.     
  282.     Try
  283.     {
  284.         //
  285.         // Next, make a specifier for "property of selection"
  286.         //
  287.         specifier = MakeSpecifierForPropertyOfSpecifier(property, selectionSpecifier);
  288.         selectionSpecifier.Dispose();
  289.     }
  290.     Catch(err)
  291.     {
  292.         //
  293.         // If 'MakeSpecifierForPropertyOfSpecifier' fails, we must dispose
  294.         // of selectionSpecifier.
  295.         //
  296.         selectionSpecifier.Dispose();
  297.         Throw(err);
  298.     }
  299.     
  300.     return specifier;
  301. } // MakeSpecifierForPropertyOfSelection 
  302.  
  303. //----------------------------------------------------------------------------------------
  304. // GetFinderSelection: 
  305. //
  306. // This routine asks the Finder for the list of selected items; 'desiredType' specifies
  307. // the data type that is desired in the result that is sent back; choices include
  308. // typeObjectSpecifier, typeFSS, and typeAlias.
  309. //----------------------------------------------------------------------------------------
  310. TDescriptor GetFinderSelection(DescType desiredType)
  311. {
  312.     TAEvent ae;
  313.     TAEvent reply;
  314.     TDescriptor target;
  315.     TDescriptor directObjectSpecifier;
  316.     TDescriptor dataDescriptor;
  317.     TDescriptor selectedItems;
  318.     OSErr err = noErr;
  319.     
  320.     Try
  321.     {
  322.         //
  323.         // Get the address of the Finder and make a "Set Data" event
  324.         //
  325.         target = GetAddressOfFinder();
  326.         ae.MakeAppleEvent(kAECoreSuite, kAEGetData, target);
  327.         target.Dispose();
  328.         
  329.         //
  330.         // Make an object specifier for the property we want to set,
  331.         // and put it into the direct object of our event
  332.         //
  333.         directObjectSpecifier = MakeSpecifierForSelection();
  334.         ae.PutDescriptor(keyDirectObject, directObjectSpecifier);
  335.         directObjectSpecifier.Dispose();
  336.         
  337.         //
  338.         // Request FSSpecs back from the Get Data event.
  339.         //
  340.         // The Object Support Library requires that the
  341.         // requested data type be stored in a list of types,
  342.         // so we coerce the 'typeType' descriptor into a list
  343.         // of one descriptor.  The Finder does not require
  344.         // this, but some other applications might, since it
  345.         // is part of the OSL spec.
  346.         //
  347.         dataDescriptor.MakeDescType(desiredType);
  348.         dataDescriptor.CoerceInPlace(typeAEList);
  349.         ae.PutDescriptor(keyAERequestedType, dataDescriptor);
  350.         dataDescriptor.Dispose();
  351.         
  352.         //
  353.         // It is generally a bad idea to use kAEWaitReply,
  354.         // because it prevents your application from processing
  355.         // other events.  There are a number of potential solutions:
  356.         //
  357.         //        Use kAEQueueReply, and process the reply when it is
  358.         //        returned from WaitNextEvent.  The disadvantage is that
  359.         //        the processing of the reply must be done separately
  360.         //        from the code that sets up to do the send
  361.         //
  362.         //        Provide a filter proc to AESend that processes
  363.         //        events while your application is waiting for the reply.
  364.         //        The disadvantage of doing this is that the event
  365.         //        handling of your application is complicated, and
  366.         //        may become nested if events need to be sent to
  367.         //        process an incoming message
  368.         //
  369.         //        Pass kImmediateTimeout as the timeout value for
  370.         //        AESend.  When the reply event is accessed, an
  371.         //        error is returned if the reply has not yet arrived.
  372.         //        This method is best employeed in conjunction with
  373.         //        a threads package, so that the thread that sends
  374.         //        the message can block until the reply arrives.
  375.         //        See the article on Futures by Michael Gough in
  376.         //        d e v e l o p  issue #7.
  377.         //
  378.         ae.Send(&reply, kAEWaitReply);
  379.         
  380.         //
  381.         // Extract the result from the reply
  382.         //    
  383.         selectedItems = reply.GetDescriptor(keyAEResult);
  384.         reply.Dispose();
  385.     }
  386.     Catch(err)
  387.     {
  388.         target.Dispose();
  389.         directObjectSpecifier.Dispose();
  390.         dataDescriptor.Dispose();
  391.         reply.Dispose();
  392.  
  393.         Throw(err);
  394.     }
  395.     
  396.     return selectedItems;
  397. } // GetFinderSelection
  398.  
  399. //----------------------------------------------------------------------------------------
  400. // CountItemsInContainer
  401. //
  402. //    Returns the number of items of class 'desiredClass' inside the specified
  403. //    container.  The target application is specified in the parameter list.
  404. //----------------------------------------------------------------------------------------
  405. long CountItemsInContainer(DescType desiredClass, TDescriptor inContainer, TDescriptor target)
  406. {
  407.     TAEvent ae;
  408.     TAEvent reply;
  409.     TDescriptor keyData;
  410.     OSErr err = noErr;
  411.     long theCount = 0;
  412.     
  413.     Try
  414.     {
  415.         //
  416.         // Make a "Count elements" event
  417.         //
  418.         ae.MakeAppleEvent(kAECoreSuite, kAECountElements, target);
  419.         
  420.         //
  421.         // Put the direct object specifier into the direct object of our event
  422.         //
  423.         ae.PutDescriptor(keyDirectObject, inContainer);
  424.         
  425.         //
  426.         // Specify the class of things we want to count
  427.         //
  428.         keyData.MakeDescType(desiredClass);
  429.         ae.PutDescriptor(keyAEObjectClass, keyData);
  430.         keyData.Dispose();
  431.         
  432.         //
  433.         // Ask the question.  kAEWaitReply without filter procs is evil.
  434.         //
  435.         ae.Send(&reply, kAEWaitReply);
  436.         
  437.         //
  438.         // Extract the result out of the reply
  439.         //
  440.         theCount = reply.GetLongParameter(keyAEResult);
  441.     }
  442.     Catch(err)
  443.     {
  444.         //
  445.         // Any of a number of routines that we call above could
  446.         // fail; if they do, we need to dispose of any object
  447.         // that we created.
  448.         //
  449.         ae.Dispose();
  450.         reply.Dispose();
  451.         keyData.Dispose();
  452.         
  453.         Throw(err);
  454.     }
  455.     
  456.     return theCount;
  457. } // CountItemsInContainer
  458.  
  459. //----------------------------------------------------------------------------------------
  460. // MakeSpecifierForAlias
  461. //----------------------------------------------------------------------------------------
  462. TDescriptor MakeSpecifierForAlias(Handle aliasHandle)
  463. {
  464.     TDescriptor specifier;
  465.     TDescriptor keyData;
  466.     TDescriptor nullContainer;
  467.     
  468.     //
  469.     // 'formAlias' is a special key form introduced by the
  470.     // Finder to allow applications to access properties of alias records
  471.     //
  472.     keyData.AdoptHandle(typeAlias, aliasHandle);    
  473.     specifier.MakeObjectSpecifier(typeWildCard, nullContainer, formAlias, keyData, false);
  474.  
  475.     return specifier;
  476. } // MakeSpecifierForAlias
  477.  
  478. void TrashWindowInformation(Handle aliasToWindowOwner, OpenWindowInfo& windowInfo);
  479.  
  480. //----------------------------------------------------------------------------------------
  481. // TrashWindowInformation
  482. //----------------------------------------------------------------------------------------
  483. void TrashWindowInformation(Handle aliasToWindowOwner, OpenWindowInfo& windowInfo)
  484. {
  485.     TAEvent ae;
  486.     TAEvent reply;
  487.     TDescriptor windowOwnerSpecifier;
  488.     TDescriptor windowOfOwnerSpecifier;
  489.     TDescriptor positionOfWindowSpecifier;
  490.     TDescriptor dataDescriptor;
  491.     TDescriptor target;
  492.     
  493.     target = GetAddressOfFinder();
  494.     
  495.     //
  496.     // Make a specifier to the window of the owner
  497.     //
  498.     windowOwnerSpecifier = MakeSpecifierForAlias(aliasToWindowOwner);
  499.     windowOfOwnerSpecifier = MakeSpecifierForPropertyOfSpecifier(windowInfo.fWindowClass,
  500.                                     windowOwnerSpecifier);
  501.     windowOwnerSpecifier.Dispose();
  502.     
  503.     //
  504.     // Move the window a bit up and left
  505.     //
  506.     OffsetRect(&windowInfo.fWindowBounds, -20, -20);
  507.     
  508.     //
  509.     // Send the Finder a set data on the window's position
  510.     //
  511.     ae.MakeAppleEvent(kAECoreSuite, kAESetData, target);
  512.     positionOfWindowSpecifier = MakeSpecifierForPropertyOfSpecifier(pBounds,
  513.                                     windowOfOwnerSpecifier);
  514.     ae.PutDescriptor(keyDirectObject, positionOfWindowSpecifier);
  515.     positionOfWindowSpecifier.Dispose();
  516.  
  517.     dataDescriptor.MakeRect(windowInfo.fWindowBounds);
  518.     ae.PutDescriptor(keyAEData, dataDescriptor);
  519.     dataDescriptor.Dispose();
  520.  
  521.     ae.Send(&reply, kAEWaitReply);
  522.     
  523.     //
  524.     // Send the Finder an "close" event
  525.     //
  526.     ae.MakeAppleEvent(kAECoreSuite, kAEClose, target);
  527.     ae.PutDescriptor(keyDirectObject, windowOfOwnerSpecifier);
  528.     
  529.     ae.Send(&reply, kAEWaitReply);
  530.     
  531.     //
  532.     // Throw away that which we do not need
  533.     //
  534.     windowOfOwnerSpecifier.Dispose();
  535.     target.Dispose();
  536. } // TrashWindowInformation
  537.  
  538. //----------------------------------------------------------------------------------------
  539. // SetWindowInformation
  540. //----------------------------------------------------------------------------------------
  541. void SetWindowInformation(Handle aliasToWindowOwner, OpenWindowInfo& windowInfo)
  542. {
  543.     TAEvent ae;
  544.     TAEvent reply;
  545.     TDescriptor windowOwnerSpecifier;
  546.     TDescriptor windowOfOwnerSpecifier;
  547.     TDescriptor positionOfWindowSpecifier;
  548.     TDescriptor dataDescriptor;
  549.     TDescriptor target;
  550.     
  551.     target = GetAddressOfFinder();
  552.     
  553.     //
  554.     // Make a specifier to the window of the owner
  555.     //
  556.     windowOwnerSpecifier = MakeSpecifierForAlias(aliasToWindowOwner);
  557.     windowOfOwnerSpecifier = MakeSpecifierForPropertyOfSpecifier(windowInfo.fWindowClass,
  558.                                         windowOwnerSpecifier);
  559.     windowOwnerSpecifier.Dispose();
  560.     
  561.     //
  562.     // Send the Finder an "open" event
  563.     //
  564.     ae.MakeAppleEvent(kCoreEventClass, kAEOpen, target);
  565.     ae.PutDescriptor(keyDirectObject, windowOfOwnerSpecifier);
  566.     
  567.     ae.Send(&reply, kAEWaitReply);
  568.     
  569.     //
  570.     // Send the Finder a set data on the window's position
  571.     //
  572.     ae.MakeAppleEvent(kAECoreSuite, kAESetData, target);
  573.     positionOfWindowSpecifier = MakeSpecifierForPropertyOfSpecifier(pBounds,
  574.                                         windowOfOwnerSpecifier);
  575.     ae.PutDescriptor(keyDirectObject, positionOfWindowSpecifier);
  576.     positionOfWindowSpecifier.Dispose();
  577.  
  578.     dataDescriptor.MakeRect(windowInfo.fWindowBounds);
  579.     ae.PutDescriptor(keyAEData, dataDescriptor);
  580.     dataDescriptor.Dispose();
  581.  
  582.     ae.Send(&reply, kAEWaitReply);
  583.     
  584.     //
  585.     // Throw away that which we do not need
  586.     //
  587.     windowOfOwnerSpecifier.Dispose();
  588.     target.Dispose();
  589. } // SetWindowInformation
  590.  
  591. //----------------------------------------------------------------------------------------
  592. // RestoreAllWindowInformation
  593. //
  594. // Assume that the resource fork at the top of the chain contains the saved window
  595. // positions
  596. //----------------------------------------------------------------------------------------
  597. void RestoreAllWindowInformation()
  598. {
  599.     short numberOfSavedWindows = Count1Resources(kOpenWindowInfoType);
  600.     
  601.     for(short i=1;i<=numberOfSavedWindows;++i)
  602.     {
  603.         OpenWindowInfoHandle infoWindowHandle = (OpenWindowInfoHandle) Get1IndResource(kOpenWindowInfoType, i);
  604.         OpenWindowInfo windowInfo = **infoWindowHandle;
  605.         
  606.         Handle aliasToWindowOwner = Get1Resource(kAliasToWindowOwnerType, windowInfo.fAliasToOwnerID);
  607.         SetWindowInformation(aliasToWindowOwner, windowInfo);
  608.     }
  609. } // RestoreAllWindowInformation
  610.  
  611. //----------------------------------------------------------------------------------------
  612. // SaveWindowInformation
  613. //
  614. // Assumes that someone already created a file, and that it's resource fork is at
  615. // the top of the resource chain.
  616. //----------------------------------------------------------------------------------------
  617. void SaveWindowInformation(Handle aliasToWindowOwner, OpenWindowInfo& windowInfo)
  618. {
  619.     short newID = Unique1ID(kAliasToWindowOwnerType);
  620.     
  621.     HandToHand(&aliasToWindowOwner);
  622.     AddResource(aliasToWindowOwner, kAliasToWindowOwnerType, newID, "\p");
  623.     windowInfo.fAliasToOwnerID = newID;
  624.     
  625.     OpenWindowInfoHandle infoWindowHandle = (OpenWindowInfoHandle) NewHandle(sizeof(OpenWindowInfo));
  626.     FailMemErrorOrNil(infoWindowHandle);
  627.     **infoWindowHandle = windowInfo;
  628.  
  629.     newID = Unique1ID(kOpenWindowInfoType);
  630.     AddResource((Handle)infoWindowHandle, kOpenWindowInfoType, newID, "\p");
  631. } // SaveWindowInformation
  632.  
  633. //----------------------------------------------------------------------------------------
  634. // SaveWindowsAndPositions
  635. //----------------------------------------------------------------------------------------
  636. void SaveWindowsAndPositions()
  637. {
  638.     TDescriptor target;
  639.     TDescriptor nullContainer;
  640.     long openWindows = 0;
  641.     OSErr err = noErr;
  642.     
  643.     Try
  644.     {
  645.         target = GetAddressOfFinder();
  646.         
  647.         //
  648.         // Ask the Finder how many windows are open
  649.         //
  650.         openWindows = CountItemsInContainer(cWindow, nullContainer, target);
  651.         
  652.         //
  653.         // Iterate once per open window
  654.         //
  655.         for(long i=1; i<=openWindows; ++i)
  656.         {
  657.             TDescriptor windowNSpecifier;
  658.             TDescriptor propertySpecifier;
  659.             TDescriptor keyData;
  660.             TDescriptor resultDescriptor;
  661.             TAEvent ae;
  662.             TAEvent reply;
  663.             Handle aliasToWindowOwner = nil;
  664.             DescType windowClass;
  665.             Rect windowBounds;
  666.  
  667.             //
  668.             // If we fail to get information on one window,
  669.             // just skip it and go on to the next
  670.             //
  671.             Try
  672.             {
  673.                 //
  674.                 // Make an object specifier for the N'th window
  675.                 //
  676.                 windowNSpecifier = MakeSpecifierForIndexedItem(cWindow, i, nullContainer);
  677.                 
  678.                 //
  679.                 // Get the folder of the open window
  680.                 //
  681.                 // We are asking for 'item of window i'; in this case, 'item'
  682.                 // refers to the item that "owns" the window.
  683.                 //
  684.                 ae.MakeAppleEvent(kAECoreSuite, kAEGetData, target);
  685.                 propertySpecifier = MakeSpecifierForPropertyOfSpecifier(cObject,
  686.                                             windowNSpecifier);
  687.                 ae.PutDescriptor(keyDirectObject, propertySpecifier);
  688.                 propertySpecifier.Dispose();
  689.                 
  690.                 //
  691.                 // We are asking for the data as an alias; this might
  692.                 // not be possible for some windows (e.g. the "About this
  693.                 // Macintosh" window or "Finder Shortcuts"; for these
  694.                 // windows, ae.Send will fail.
  695.                 //
  696.                 keyData.MakeDescType(typeAlias);
  697.                 keyData.CoerceInPlace(typeAEList);
  698.                 ae.PutDescriptor(keyAERequestedType, keyData);
  699.                 keyData.Dispose();
  700.                 
  701.                 ae.Send(&reply, kAEWaitReply);
  702.                 
  703.                 resultDescriptor = reply.GetDescriptor(keyAEResult);
  704.                 aliasToWindowOwner = resultDescriptor.DataHandle();
  705.                 resultDescriptor.MakeNull();
  706.                 
  707.                 //
  708.                 // Get the class of the open window
  709.                 //
  710.                 ae.MakeAppleEvent(kAECoreSuite, kAEGetData, target);
  711.                 propertySpecifier = MakeSpecifierForPropertyOfSpecifier(pClass,
  712.                                                 windowNSpecifier);
  713.                 ae.PutDescriptor(keyDirectObject, propertySpecifier);
  714.                 propertySpecifier.Dispose();
  715.     
  716.                 ae.Send(&reply, kAEWaitReply);
  717.                 
  718.                 resultDescriptor = reply.GetDescriptor(keyAEResult);
  719.                 windowClass = resultDescriptor.GetDescType();
  720.                 resultDescriptor.Dispose();
  721.                 
  722.                 //
  723.                 // Get the position of the open window
  724.                 //
  725.                 ae.MakeAppleEvent(kAECoreSuite, kAEGetData, target);
  726.                 propertySpecifier = MakeSpecifierForPropertyOfSpecifier(pBounds,
  727.                                                 windowNSpecifier);
  728.                 ae.PutDescriptor(keyDirectObject, propertySpecifier);
  729.                 propertySpecifier.Dispose();
  730.     
  731.                 ae.Send(&reply, kAEWaitReply);
  732.     
  733.                 resultDescriptor = reply.GetDescriptor(keyAEResult);
  734.                 windowBounds = resultDescriptor.GetRect();
  735.                 resultDescriptor.Dispose();
  736.  
  737.                 //
  738.                 // Make a window info structure
  739.                 //
  740.                 OpenWindowInfo theWindowInfo;
  741.                 theWindowInfo.fWindowClass = windowClass;
  742.                 theWindowInfo.fWindowBounds = windowBounds;
  743.                                 
  744.                 //
  745.                 // Save all of that information somewhere
  746.                 //
  747.                 SaveWindowInformation(aliasToWindowOwner, theWindowInfo);
  748.                 
  749.                 //
  750.                 // Dispose the window specifier and continue
  751.                 //
  752.                 windowNSpecifier.Dispose();
  753.             }
  754.             Catch(err)
  755.             {
  756.                 //
  757.                 // Clean up before we go around again
  758.                 //
  759.                 keyData.Dispose();
  760.                 propertySpecifier.Dispose();
  761.                 resultDescriptor.Dispose();
  762.                 windowNSpecifier.Dispose();
  763.             }
  764.         }
  765.         
  766.         //
  767.         // Done with the target
  768.         //
  769.         target.Dispose();
  770.     }
  771.     Catch(err)
  772.     {
  773.         //
  774.         // Any of a number of routines that we call above could
  775.         // fail; if they do, we need to dispose of any object
  776.         // that we created.
  777.         //
  778.         target.Dispose();
  779.     }
  780. } // SaveWindowsAndPositions
  781.  
  782. //----------------------------------------------------------------------------------------
  783. // UpdateChangedObject: 
  784. //----------------------------------------------------------------------------------------
  785. void UpdateChangedObject(FSSpec& itemsFSSpec)
  786. {
  787.     TAEvent ae;
  788.     TAEvent reply;
  789.     TDescriptor target;
  790.     TDescriptor directObjectSpecifier;
  791.     OSErr err = noErr;
  792.     
  793.     Try
  794.     {
  795.         //
  796.         // Get the address of the Finder and make an "Update" event
  797.         //
  798.         target = GetAddressOfFinder();
  799.         ae.MakeAppleEvent(kAEFinderSuite, kAEUpdate, target);
  800.         target.Dispose();
  801.         
  802.         //
  803.         // Most scriptable applications require the direct
  804.         // object of an event to always be an object
  805.         // specifier.  The Finder is special, though; it
  806.         // will accept FSSpecs and alias records as well.
  807.         //
  808.         directObjectSpecifier.MakeFSS(itemsFSSpec);
  809.         ae.PutDescriptor(keyDirectObject, directObjectSpecifier);
  810.         directObjectSpecifier.Dispose();
  811.         
  812.         //
  813.         // The reply isn't actuall filled in due to the kAENoReply flag
  814.         //
  815.         ae.Send(&reply, kAENoReply);
  816.     }
  817.     Catch(err)
  818.     {
  819.         //
  820.         // Any of a number of routines that we call above could
  821.         // fail; if they do, we need to dispose of any object
  822.         // that we created.
  823.         //
  824.         target.Dispose();
  825.         directObjectSpecifier.Dispose();
  826.         ae.Dispose();
  827.         
  828.         Throw(err);
  829.     }
  830. } // UpdateChangedObject
  831.  
  832.